/*
 Ajanta - Java Linear Programming Library

 Copyright 2010 Raghu Kaippully.

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 */
package logic.simplex.solver.internal.simplex;

import java.util.HashMap;
import java.util.Map;
import logic.simplex.model.LPVariable;

/**
 * Column or Row labels of a {@link Tableau}.
 *
 * <p/>
 * This class provides methods to efficiently find out which LP variable uses a
 * given column/row of the tableau or which column/row is used for a given LP
 * variable.
 */
public class TableauLabel {

    /**
     * Mapping between an LP variable and it's column/row index
     */
    private Map<LPVariable, Integer> variable2Index;
    /**
     * Mapping between a column/row index and an LP variable
     */
    private LPVariable[] index2Variable;

    /**
     * Create a TableauLabel by specifying it's maximum size.
     *
     * @param size maximum size of this label
     */
    public TableauLabel(int size) {
        variable2Index = new HashMap<LPVariable, Integer>(size);
        index2Variable = new LPVariable[size];
    }

    /**
     * Returns the index of this variable. If the variable is not yet added to
     * the column or row, it will be added now at the next available slot.
     *
     * @param variable the variable to get the index of
     * @return the index of the variable in the column or row label
     */
    public int getOrAddIndex(LPVariable variable) {
        Integer index = variable2Index.get(variable);
        if (index == null) {
            index = variable2Index.size();
            setVariable(variable, index);
        }
        return index;
    }

    /**
     * Returns the index of this variable. If the variable is not yet added to
     * the column or row this method return -1.
     *
     * @param variable the variable to get the index of
     * @return the index of the variable in the column or row label or -1 is the
     * variable is not added to this label
     */
    public int getIndex(LPVariable variable) {
        Integer index = variable2Index.get(variable);
        return index == null ? -1 : index;
    }

    /**
     * Adds the specified variable at the specified index location in this
     * label. If another variable is present at that location it will be
     * overwritten.
     *
     * @param variable the variable to add
     * @param index the index at which the variable must be added
     */
    public void setVariable(LPVariable variable, Integer index) {
        Integer previousIndex = variable2Index.put(variable, index);
        if (previousIndex != null) {
            index2Variable[previousIndex] = null;
        }
        index2Variable[index] = variable;
    }

    /**
     * Returns the variable located at the specified index of this label.
     *
     * @param index the index to get the variable from
     * @return the variable located at the specified index of this label.
     * @throws IndexOutOfBoundsException if index is outside the range
     */
    public LPVariable getVariable(int index) {
        return index2Variable[index];
    }
}
